
#ifndef Vector2D_H
#define Vector2D_H

//Standard library headers
#include <math.h>
#include <iostream>

#define PI 3.14159265358979323846

//Operator definitions
//  Dot product =   	%
//  2D cross product = 	^

class Vector2D;

//std::ostream& operator <<(std::ostream &os, Vector2D& obj);

class Vector2D
{

    public:

	//Scaler type definition
	typedef double scalar;

    private:
    
    //Array to hold vector data
	scalar V[2];
	
    public:

	//Initalisation constructor
	Vector2D(scalar X = 0, scalar Y = 0) { V[0]=X; V[1]=Y; }
	
	
	//Array access operator
	scalar operator [] (const unsigned i) const	{ return V[i]; }
	scalar &operator [] (const unsigned i) { return V[i]; }
	
	//Copy constructor
	Vector2D(const Vector2D &vec) { V[0]=vec[0]; V[1]=vec[1]; }
	
	//Function to return vector array
	scalar* getArray()					{ return V; }
	
	//Element access functions
	scalar x()	const				{ return V[0]; }
	scalar y()	const				{ return V[1]; }
	scalar &x()						{ return V[0]; }
	scalar &y()						{ return V[1]; }
	
	//friend std::ostream& operator <<(std::ostream &os,const Vector2D &obj);
	
	//Vector assignment
	const Vector2D &operator = (const Vector2D &vec)
	{
	    V[0] = vec[0];
	    V[1] = vec[1];
		
	    return *this;
	}
	
	//Scalar assignment
	const Vector2D &operator = (const scalar &s)
	{
	    V[0] = s;
	    V[1] = s;
		
	    return *this;
	}
	
	//Vector equality
	const bool operator == (const Vector2D &vec) const
	{
	    return ((V[0] == vec[0]) && (V[1] == vec[1]));
	}
	
	//Vector inequality
	const bool operator != (const Vector2D &vec) const
	{
	    return !(*this == vec);
	}
	
	//Vector add
	const Vector2D operator + (const Vector2D &vec) const
	{
	    return Vector2D(V[0] + vec[0], V[1] + vec[1]);
	}
	
	//Vector add (opposite of negation)
	const Vector2D operator + () const
	{    
	    return Vector2D(*this);
	}
	
	//Vector increment
	const Vector2D& operator += (const Vector2D& vec)
	{    
	    V[0] += vec[0];
	    V[1] += vec[1];
	  	
	    return *this;
	}
	
	//Vector subtraction
	const Vector2D operator - (const Vector2D& vec) const
	{    
	    return Vector2D(V[0] - vec[0], V[1] - vec[1]);
	}
	
	//Vector negation
	const Vector2D operator - () const
	{    
	    return Vector2D(-V[0], -V[1]);
	}
	
	//Vector decrement
	const Vector2D &operator -= (const Vector2D& vec)
	{
	    V[0] -= vec[0];
	    V[1] -= vec[1];
	
	    return *this;
	}
	
	//scalar self-multiply
	const Vector2D &operator *= (const scalar &s)
	{
	    V[0] *= s;
	    V[1] *= s;
	  
	    return *this;
	}
	
	//Scalar self-divide
	const Vector2D &operator /= (const scalar &s)
	{
	    const scalar recip = 1/s; // for speed, one divecision
	
	    V[0] *= recip;
	    V[1] *= recip;
	
	    return *this;
	}
	
	//Post multiply by scalar
	const Vector2D operator * (const scalar &s) const
	{
	    return Vector2D(V[0]*s, V[1]*s);
	}
	
	//Pre multiply by scalar
	friend inline const Vector2D operator*(const scalar &s, const Vector2D &vec)
	{
	    return vec*s;
	}
	
	//Divide by scalar
	const Vector2D operator / (scalar s) const
	{
	    s = 1/s;
	
	    return Vector2D(s*V[0], s*V[1]);
	}
	
	//Dot product
	const scalar DotProduct(const Vector2D &vec) const
	{
	    return V[0]*vec[0] + V[1]*vec[1];
	}
	
	//Dot product
	const scalar operator % (const Vector2D &vec) const
	{
	    return V[0]*vec[0] + V[1]*vec[1];
	}
	
	//2D cross product
	const scalar CrossProduct (const Vector2D &vec) const
	{
	    return (V[0]*vec[1] - V[1]*vec[0]);
	}
	
	//2D cross product
	const scalar operator ^ (const Vector2D &vec) const
	{
	    return (V[0]*vec[1] - V[1]*vec[0]);
	}
	
	//Length of vector
	const scalar getLength() const
	{
	    return (scalar)sqrt((double)(V[0]*V[0] + V[1]*V[1]));
	}
	
	//Length squared of vector
	const scalar getLength2() const
	{
	    return (scalar)(double)(V[0]*V[0] + V[1]*V[1]);
	}
	
	//Return the unit vector
	const Vector2D getUnitVector() const
	{
	    return (*this) / getLength();
	}
	
	//Return the 2D normal vector
	const Vector2D getNormal() const
	{
	    return Vector2D(V[1], -V[0]);
	}
	
	//Normalise this vector
	void normalize()
	{
	    (*this) /= getLength();
	}
	
	//Return angle of vector in degrees
	const scalar getAngle() const
	{
		/*
	    if (V[0] == 0){
		if (V[1] > 0)
		    return -90;
		else
		    return 90;
	    }
		
	    scalar a = (scalar)atan((double)(V[1] / V[0])) * 180 / PI;
		
	    if (V[0] > 0.0f)
		return (a + 180);
	    else
		return a;*/
		
		
	    if (!V[0])
    		if (V[1] > 0)
    		    return -PI/2.f;
    		else
    		    return PI/2.f;
		
	    scalar a = (scalar)atan((double)(V[1] / V[0]));
		
	    if (V[0] > 0.0f)
		  return (a + PI);
	    else
		  return a;
		
	}
	
	//Zero the vector 
	void zero()
	{
		
	    V[0] = 0;
	    V[1] = 0;
		
	}
	
	//Determine if vector is zero
	const bool isZero() const
	{
	    return ((V[0] == 0) && (V[1] == 0));
	}
	
	/*//Return vector with specified length
	const Vector2D operator | (const scalar length) const
	{
	return *this * (length / !(*this));
}*/
	
	/*// set length of Vector2D equal to length
	const Vector2D& operator |= (const float length)
	{
	return *this = *this | length;
}*/
	
	// return angle between two vectors
	/*const float inline Angle(const Vector2D& normal) const
	{
	return acosf(*this % normal);
}*/
	
	// reflect this vector off surface with normal vector
	/*const Vector2D inline Reflection(const Vector2D& normal) const
	{
	const Vector2D vec(*this | 1);     // normaliV[2]e this Vector2D
	return (vec - normal * 2.0 * (vec % normal)) * !*this;
}*/

};

//Stream operators
/*std::ostream& operator <<(std::ostream &os, Vector2D& obj)
{
      os << obj[0] << ", " << obj[1] << ", " << obj[2];
      return os;
}*/

#endif
